package gases.as3.librarys.core.net.socket
{
	import cn.qicool.game.wx2.bundle.socketcpp.events.SocketEvent;
	
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.utils.ByteArray;
	

	public class BytesSocket extends BaseSocket
	{
		public function BytesSocket(host:String = null, port:int = 0, securityPort:int = 0)
		{
			super(host, port, securityPort);
		}
		
		override protected function initialize():void
		{
			super.initialize();
			_decodeBytes = new Array();
			_tempByte = new ByteArray();
		}
		/**
		 * 
		 * @param byte
		 * @param isSend
		 * 重写writeInSocket,用来传输对象
		 * 
		 */		
		override public function writeInSocket(byte:Object, isSend:Boolean=true):void
		{
			/*
			1.未压缩的包结构(包头4字节) ¶数据长度	数据内容 
			4byte	命令长度(去掉包头后) 
			1byte	留空 
			1byte	是否为压缩包 
			bytes 	命令内容 
			bytes	补足内容 
			
			2.压缩过的包结构(包头6字节)数据长度	数据内容 
			4byte	压缩过后的命令长度(去掉包头后) 
			1byte	留空 
			1byte	是否为压缩包 
			4byte	解压缩后的命令长度(去掉包头后) 
			bytes 	已经压缩命令内容 
			bytes	补足内容
			*/
			var bytes:ByteArray = byte as ByteArray;
			if(bytes)
			{
				if(connected)
				{
					var sendBytes:ByteArray = makeSendBytes(bytes);
					_socket.writeBytes(sendBytes);
					if(isSend)
						send();
				}
				else
				{
					_buffers.push(bytes);
				}
			}
		}
		
		private function makeSendBytes(bytes:ByteArray):ByteArray
		{
			var sendBytes:ByteArray = new ByteArray();
			SocketUtil.writeInt(bytes.length,sendBytes);
			sendBytes.writeByte(0);
			sendBytes.writeByte(0);
			sendBytes.writeBytes(bytes,0,bytes.length);
			var pleg:int = sendBytes.length;
			var pp:int = Math.floor(((pleg+7)/8))*8 - pleg;
			for(var i:int =0;i<pp;i++)
			{
				sendBytes.writeByte(0);
			}
			return sendBytes;
		}
		
		/**
		 * 获取初步解析完的一组数据 
		 * @return 
		 * 
		 */		
		public function getByte():ByteArray
		{
			if(_decodeBytes.length > 0)
				return ByteArray(_decodeBytes.shift());
			return null;
		}
		
		/**
		 * 获取解析数组长度
		 * @return 
		 * 
		 */		
		public function getByteLength():int
		{
			return _decodeBytes.length;
		}

		override protected function resolveSocketData():void
		{
			if(_socket.bytesAvailable < _needByteLength)
				return;
			if(_isRecving)
			{
				if(_isCompressed && _cmdLength + 4 > _socket.bytesAvailable)
				{
					return;
				}
				if(!_isCompressed && _cmdLength > _socket.bytesAvailable)
				{
					return;
				}
				if(_isCompressed)
				{
					_contentLength = SocketUtil.readInt(_socket);
				}
				else
				{
					_contentLength = _cmdLength;
				}
				
				var cmdByte:ByteArray = new ByteArray();
				_socket.readBytes(cmdByte, 0, _cmdLength);
				if(_isCompressed)
				{
					cmdByte.uncompress();
				}
				if(_contentLength != cmdByte.length)
				{
					throw('cmd package contente uncompress error!');
				}
				
				if(connected && _dummyBytes!=0)
					_socket.readBytes(_tempByte, 0, _dummyBytes);
				
				decode(cmdByte);
				//cmdByte.clear();
				//cmdByte = null;
				_needByteLength = 0;
				_isRecving = false;
				
				if(connected && _socket.bytesAvailable>0)
					resolveSocketData();
			}
			else
			{
				if(_socket.bytesAvailable > _minByteLength)
				{
					_isRecving = true;
					_cmdLength = SocketUtil.readInt(_socket);
					var emptyMark:int =_socket.readByte();
					var isCompressed:int = _socket.readByte();	
					_isCompressed = (isCompressed != 0 ? true : false);
					if(_isCompressed)
					{
						_needByteLength = _cmdLength;
						_dummyBytes = 8 - (_needByteLength+10) % 8;
						if(	_dummyBytes == 8)
							_dummyBytes = 0;
						_needByteLength += _dummyBytes;
						//trace('这是一个压缩包,包长度',_cmdLength+6,'命令长度',_cmdLength,'补偿长度',_dummyBytes);
					}
					else
					{
						_needByteLength = _cmdLength;
						_dummyBytes = 8 -  (6 + _needByteLength) % 8//8-(pkg_needBytes+4) % 8;
						if(	_dummyBytes == 8)
							_dummyBytes = 0;
						_needByteLength += _dummyBytes;	
						//trace('这是一个非压缩包,包长度',_cmdLength+6,'命令长度',_cmdLength,'补偿长度',_dummyBytes);
					}
					
					if(this.connected && _socket.bytesAvailable>0)
						resolveSocketData();
				}
			}
		}
		
		/**
		 * 
		 * @param byte
		 * 编码字节数组放入一个字节数组，并且触发一个事件 SocketEvent.SOCKET_BYTES_UPDATE
		 * （socket_bytes更新事件);
		 */		
		private function decode(byte:ByteArray):void
		{
			_decodeBytes.push(byte);
			this.dispatchEvent(new SocketEvent(SocketEvent.SOCKET_BYTES_UPDATE));
		}
		/**
		 * 
		 * @param event
		 * 下面依次都是重写的关闭事件，连接事件，报错事件，连接到沙箱外的事件
		 * 
		 */		
		override protected function closeHandler(event:Event):void
		{
			super.closeHandler(event);
			this.dispatchEvent(new SocketEvent(SocketEvent.SOCKET_CLOSE));
		}
		
		override protected function connectHandler(event:Event):void
		{
			super.connectHandler(event);
			this.dispatchEvent(new SocketEvent(SocketEvent.SOCKET_CONNECT));
		}
		
		override protected function ioErrorHandler(event:IOErrorEvent):void
		{
			super.ioErrorHandler(event);
		}
		
		override protected function securityErrorHandler(event:SecurityErrorEvent):void
		{
			super.securityErrorHandler(event);
		}
		
		override public function clearBuffer():void
		{
			while(_buffers.length > 0)
			{
				var byte:ByteArray = _buffers.shift() as ByteArray;
				if(byte)
					byte.clear();//清除byte里内容从而释放内存空间
			}
		}
		
		/**
		 * 覆盖了父类BaseSocket的dispose,在处理添加的socket事件时要进行内存释放处理 
		 * 
		 */		
		override public function dispose():void
		{
			_tempByte.clear();
			_tempByte = null;
			while(_decodeBytes.length > 0)
			{
				var byte:ByteArray = (_decodeBytes.pop() as ByteArray);
				if(byte)
					byte.clear();
			}
			_decodeBytes = null;
			super.dispose();
		}
		
		private var _minByteLength:int = 6;
		private var _needByteLength:int = 0;
		private var _isRecving:Boolean = false;//是否接受
		private var _cmdLength:int = 0;
		private var _isCompressed:Boolean = false;
		private var _dummyBytes:int = 0;
		private var _contentLength:int = 0;
		private var _tempByte:ByteArray;//临时字节数组
		private var _decodeBytes:Array;//编码数组
	}
}